<?php
/**
 * Created by PhpStorm.
 * User: wangjiangtao
 * Date: 2022/7/14
 * Time: 18:37
 */

namespace App\Modules\Popularize\Platform;

use App\Http\Model\Device;
use App\Http\Model\User;
use App\Http\Model\UserRegisterLog;
use Illuminate\Support\Facades\Redis;

class PlatformVivo implements PlatformInterface {

    protected $callback;
    protected $platform;
    protected $device;
    protected $userId;
    protected $requestId;
    protected $creativeId;
    protected $oaidHash;
    protected $imeiHash;

    protected $redisPay = 'ADVERTISEMENT:VIVO:PAY:%s'; //汇报记录，防止多次汇报

    const ACTIVITE_EVENT = 'ACTIVATION';
    const REGISTER_EVENT = 'REGISTER';
    const PAY_EVENT = 'PAY';
    const PAY_ONETIME_EVENT = 'PAY_ONETIME';
    const SRC_TYPE = 'app';
    const SRC_ID = 'ds-202303307922';
    const CLIENT_ID = '20230418032';
    const CLIENT_SECRET = 'C6B13C64C583E7BEE12324A13D92F27E8F488339D0654DB30040281B809C00FF';
    const ADVERTISER_ID = '4ee80846ed65406b20d7';
    const PKGNMAME = 'com.hangyu.yuanyinAudio';
    
    public function __construct($callback,$platfrom, $device, $userId)
    {
        $this->callback = $callback;
        $this->platform = $platfrom;
        $this->device = $device;
        $this->userId = $userId;
        $queryInfo = $this->_getRequestIdAndCreativeIdFromUrl($this->callback);
        if ($queryInfo != null){
            $this->requestId = $queryInfo['request_id']??'';
            $this->creativeId = $queryInfo['creative_id']??'';
            if (!empty($this->device)) {
                $this->oaidHash = $queryInfo['oaid']??'';
                $this->imeiHash = $queryInfo['imei']??'';
            }
        }
    }

    public function active():?bool
    {
        $requestData = $this->_buildRequestData(self::ACTIVITE_EVENT);
        if (empty($requestData)) {
            return false;
        }
        $params = json_decode(json_encode($this->device),true);
        $params = $this->_checkField($params);
        try {
            if (isset($this->device->guid) && $this->device->guid != ''){
                //查询是否存在设备信息，如果存在就说明设备已经激活
                $deviceModel = new Device();
                $deviceInfo = $deviceModel->getByGuid($this->device->guid);
                if(!empty($deviceInfo)){
                    write_log('Platform', 'platform_vivo', ["设备已存在", $params]);
                    return false;
                }
                $deviceModel->save($params);

                //获取用户注册并修改渠道
                $model = new UserRegisterLog();
                $userRegisterLog = $model->findRecordByGuid($this->device->guid, ['user_id']);
                if ($userRegisterLog && $this->platform != '' && is_numeric($userRegisterLog['platform']) && $userRegisterLog['platform'] == $userRegisterLog['channel_id']) {
                    $model->updatePlatform($userRegisterLog['user_id'], $this->platform);
                }

                write_log('Platform', 'platform_vivo', ["保存设备信息成功", $params]);
                return $this->_report(self::ACTIVITE_EVENT, $requestData);
            }
        } catch (\Exception $e) {
            write_log('Platform', 'platform_vivo', ["保存设备信息失败", $params,$e->getMessage()]);
            return false;
        }
        return true;
    }

    public function regist():?bool
    {
        $requestData = $this->_buildRequestData(self::REGISTER_EVENT);
        if (empty($requestData)) {
            return false;
        }
        return $this->_report(self::REGISTER_EVENT, $requestData);
    }

    public function pay($amount = 0):?bool
    {
        //规定时间内注册且付费才上报
        $user = (new User())->get_user($this->userId,true);
        if(time() - $user['create_timestamp'] > 86400){
            return true;
        }

        $key = sprintf($this->redisPay,$this->userId);
        $exists = Redis::get($key);
        if(empty($exists)){
            //只提交一次
            $requestData = $this->_buildRequestData(self::PAY_EVENT, $amount);
            if (empty($requestData)) {
                return false;
            }
            $this->_report(self::PAY_EVENT, $requestData);
            Redis::setex($key, 86400 * 4, 1);
        }

        //每次都提交
        $requestData = $this->_buildRequestData(self::PAY_ONETIME_EVENT, $amount);
        if (empty($requestData)) {
            return false;
        }
        $this->_report(self::PAY_ONETIME_EVENT, $requestData);

        return true;
    }

    /**
     * 获取设备信息
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|void|null
     */
    public function getDevice(){
        return $this->device;
    }

    private function _buildRequestData($type, $payAmount = 0){
        $userIdType = '';
        $deviceNo = '';
        if (isset($this->oaidHash) && !empty($this->oaidHash) && $this->oaidHash != 'UNKNOWN'){
            $userIdType = 'OAID_MD5';
            $deviceNo = $this->oaidHash;
        } else if (isset($this->imeiHash) && !empty($this->imeiHash) && $this->imeiHash != 'UNKNOWN'){
            $userIdType = 'IMEI_MD5';
            $deviceNo = $this->imeiHash;
        }  else {
            return null;
        }

        if (empty($userIdType)) {
            write_log("Advertisement", "platform_vivo", ["empty device info", $this->device]);
            return null;
        }
        if (empty($this->requestId) || empty($this->creativeId))  {
            return null;
        }
        $dataList = [
            'userIdType' => $userIdType,
            'userId' => $deviceNo,
            'cvType' => $type,
            'cvTime' => time() * 1000,
            'cvParam' => $payAmount,
            'requestId' => $this->requestId,
            'creativeId' => $this->creativeId,
        ];
        return [
            'srcType' => self::SRC_TYPE,
            'srcId' => self::SRC_ID,
            'pkgName' => self::PKGNMAME,
            'dataList' => $dataList,
        ];
    }

    //上报vivo服务器
    private function _report($type, $requestData){
        if (empty($requestData)) {
            return false;
        }
        $accessToken = $this->_getToken();
        if (empty($accessToken)) {
            return false;
        }
        $callback = sprintf("%s&access_token=%s&timestamp=%s&nonce=%s&advertiser_id=%s",
            $this->callback, $accessToken, time()* 1000, $this->_createSign($requestData, time()) ,self::ADVERTISER_ID);
        try{
            $header = ['Content-Type' => 'application/json'];
            $result = curl_request($callback, $requestData, 'json', 'POST', $header);
            write_log('Advertisement', 'platform_vivo_success', [$type, $callback, $requestData, $result]);
        }catch (\Exception $exception){
            write_log('Advertisement', 'platform_vivo_error', [$type, $callback, $requestData, $result]);
            return false;
        }
        $result = json_decode($result);

        return isset($result->code) &&  $result->code == 0;
    }

    //    以下是获取token
    //    "access_token": "8cc6701b89eabe5719c82750541e183addbcace90c31a3ac13b61a2cd887f844",
    //    "refresh_token": "c198915159169ecec07b7108654cf90081ac051f66b80a6eb55bae4751d9291e",
    //    "token_date": 1691920493383,
    //    "refresh_token_date": 1692352493383
    //    vivo技术最棒，vivo技术最强大，下个手机换!vivo
    private function _getToken(){
        $accessTokenRedisKey = 'ADVERTISEMENT:VIVO:TOKEN';
        $accessDate = Redis::hget($accessTokenRedisKey, "token_date");
        if (empty($accessDate)) {
            write_log('Advertisement', 'platform_vivo', ['Get TokenDate Failed']);
            return null;
        }
        $accessDate = floor($accessDate / 1000);
        if ($accessDate - time() > 30 * 3600 * 24) {
            $accessToken = Redis::hget($accessTokenRedisKey, "access_token");
            if (empty($accessToken)) {
                write_log('Advertisement', 'platform_vivo', ['Get AccessToken Failed']);
                return null;
            }
            return $accessToken;
        }
        //开始请求vivo服务器，刷新token，
        //如果拿不到就直接返回吧，别挣扎
        $refreshToken = Redis::hget($accessTokenRedisKey, "refresh_token");
        if (empty($refreshToken)) {
            write_log('Advertisement', 'platform_vivo', ['Get RefreshToken Failed']);
            return null;
        }
        $refreshUrl = 'https://marketing-api.vivo.com.cn/openapi/v1/oauth2/refreshToken';
        $params = [
            'client_id' => self::CLIENT_ID,
            'client_secret' => self::CLIENT_SECRET,
            'refresh_token' =>$refreshToken,
        ];
        $result = curl_request($refreshUrl, $params, 'urlencoded', 'GET');
        $result = json_decode($result);
        //如果拿不到就直接返回吧，别挣扎
        if (!isset($result->code) || $result->code != 0) {
            write_log('Advertisement', 'platform_vivo', ['Get Access Token Error', $result]);
            return null;
        }
        $accessToken = isset($result->data->access_token)??'';
        $refreshToken = isset($result->data->refresh_token)??'';;
        $accessDate = isset($result->data->token_date)??'';
        $refreshDate = isset($result->data->refresh_token_date)??'';
        Redis::hset($accessTokenRedisKey, 'access_token', $accessToken);
        Redis::hset($accessTokenRedisKey, 'refresh_token', $refreshToken);
        Redis::hset($accessTokenRedisKey, 'token_date', $accessDate);
        Redis::hset($accessTokenRedisKey, 'refresh_token_date', $refreshDate);
        Redis::EXPIRE($accessTokenRedisKey, 365 * 24 * 3600);
        return  $accessToken;
    }

    private function _getRequestIdAndCreativeIdFromUrl($url){
        if (empty($url)){
            return null;
        }
        $urlinfo = parse_url($url);
        if (empty($urlinfo)) {
            return null;
        }
        parse_str( $urlinfo['query'], $queryInfo);
        if (!isset($queryInfo['request_id'])  || empty($queryInfo['request_id'])
            || !isset($queryInfo['creative_id'])  || empty($queryInfo['creative_id'])) {
            return null;
        }
        return $queryInfo;
    }

    protected function _checkField($params = []) {
        do {
            $checkField = ['cid', 'aid', 'callback','advertiser_id', 'guid', 'idfa', 'version_no', 'os_name', 'device', 'channel_id', 'platform','imei','oaid','adid','conv_ext', 'client_ip'];
            if (empty($params)) {
                break;
            }

            $inputParams = [];
            foreach ($checkField as $field) {
                if (array_key_exists($field, $params)) {
                    $inputParams[$field] = $params[$field];
                }
            }

            $params = $inputParams;
        } while (false);

        return $params;
    }

    private function _createSign($postData,$time,$salt = 'e0u6fnlag06lc3pl'){
        $data = json_encode($postData).$time.$salt;
        return md5($data);
    }
}
